//
// Created by francklinson on 2021/10/24 AT 10:38.
//


#ifndef CPPLEETCODING_VECTOR_H
#define CPPLEETCODING_VECTOR_H

#include <algorithm>

/**
 * 实质上是保存了Vector的数据指针
 * @tparam Vector
 */
template<typename Vector>
class VectorIterator {
public:
    using ValueType = typename Vector::ValueType;
    using PointerType = ValueType *;
    using ReferenceType = ValueType &;

    VectorIterator(PointerType ptr)
            : m_Ptr(ptr) {

    };

    // ++i
    VectorIterator &operator++() {
        m_Ptr++;
        return *this;
    }

    // i++
    VectorIterator operator++(int) {
        VectorIterator iterator = *this;
        ++(*this); // 调用++i
        return iterator;
    }

    // --i
    VectorIterator &operator--() {
        m_Ptr--;
        return *this;
    }

    // i--
    VectorIterator operator--(int) {
        VectorIterator iterator = *this;
        --(*this); // 调用--i
        return iterator;
    }

    ReferenceType operator[](int index) {
        return *(m_Ptr + index);
    }

    PointerType operator->() {
        return m_Ptr;
    }

    ReferenceType operator*() {
        return *m_Ptr;
    }

    bool operator==(const VectorIterator &other) const {
        return m_Ptr == other.m_Ptr;
    }

    bool operator!=(const VectorIterator &other) const {
        return !(*this == other);
    }

private:
    PointerType m_Ptr;
};

template<typename T>
class Vector {
public:
    using ValueType = T;
    using Iterator = VectorIterator<Vector<T>>; // 专用迭代器

    Vector() {
        ReAlloc(2);
    }

    ~Vector() {
        // vector 析构的时候，先调用了Clear，调用了每个元素的析构函数，未释放空间
        Clear();
        // 再进行delete[]，还会调用每个元素的析构函数
        // 这个时候，元素的析构函数就被调用两遍，如果元素中含有new出来的堆上的数据，就会报错
        // 所以，在clear后，只需要把空间释放，而不需要再delete[]
//        delete[] m_Data;
        ::operator delete(m_Data, m_Capacity * sizeof(T));
    }

    // 添加元素到末尾
    void PushBack(const T &value) {
        // 如果当前容量不足，增加50%
        if (m_Size >= m_Capacity) {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        m_Data[m_Size] = value;
        ++m_Size;
    }

    // 添加元素到末尾
    void PushBack(T &&value) {
        // 如果当前容量不足，增加50%
        if (m_Size >= m_Capacity) {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        m_Data[m_Size] = std::move(value);
        ++m_Size;
    }

    template<typename ... Args>
    T &EmplaceBack(Args &&...args) {
        if (m_Size >= m_Capacity) {
            ReAlloc(m_Capacity + m_Capacity / 2);
        }
        new(&m_Data[m_Size])T(std::forward<Args>(args)...); // construction in place
//        m_Data[m_Size] = T(std::forward<Args>(args)...);// move
        return m_Data[m_Size++];
    }

    // 弹出最后一个元素
    void PopBack() {
        if (m_Size > 0) {
            m_Size--;
            m_Data[m_Size].~T();
        }
    }

    // 返回最后一个元素的引用
    T &Back() {
        return m_Data[m_Size - 1];
    }

    const T &Back() const {
        return m_Data[m_Size - 1];
    }

    // 清除所有元素
    void Clear() {
        for (size_t i = 0; i < m_Size; ++i)
            m_Data[i].~T(); // 逐个调用析构函数
        m_Size = 0;
    }

    // 返回常量引用
    const T &operator[](size_t index) const {
        return m_Data[index];
    }

    // 返回可修改的左值引用
    T &operator[](size_t index) {
        return m_Data[index];
    }

    // 返回当前数组大小
    [[nodiscard]] size_t Size() const {
        return m_Size;
    }

    Iterator begin() {
        return Iterator(m_Data);
    }

    Iterator end() {
        return Iterator(m_Data + m_Size);
    }

private:
    // 分配内存空间
    void ReAlloc(size_t newCapacity) {
        // 1.allocate a new block of memory
        // 2.copy/move old elements into new block
        // 3.delete

//        T *newBlock = new T[newCapacity];
        // 只开辟空间 不进行初始化
        T *newBlock = (T *) ::operator new(newCapacity * sizeof(T));
        // 如果新的容量小于现有容量
        if (newCapacity < m_Size)
            m_Size = newCapacity;

        for (size_t i = 0; i < m_Size; ++i) {
            // 直接将原值move走 因为原来的数据空间需要被释放了
            new(&newBlock[i])T(std::move(m_Data[i]));
//            newBlock[i] = std::move(m_Data[i]); // 只开辟了空间 没有调用构造函数
        }
//        delete[] m_Data; //delete[] 操作符 调用析构函数并释放空间
        size_t oldSize = m_Size;
        Clear(); // 逐个调用析构函数  clear会清空m_Size计数器 只能额外存储
        m_Size = oldSize;
        ::operator delete(m_Data, m_Capacity * sizeof(T)); // 释放空间
        m_Data = newBlock;
        m_Capacity = newCapacity;
    }

private:
    T *m_Data = nullptr;
    size_t m_Size = 0; // 现有规模
    size_t m_Capacity = 0; // 当前最大容量
};


#endif //CPPLEETCODING_VECTOR_H
